package models

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"gitchina/kly_service/data"
	"gitchina/kly_service/template"
	"gitchina/kly_service/util"
	"golang.org/x/net/html/charset"
	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

type InsuranceRecord struct {
	MemberId  int
	WaybillId int
	Amount    float32
	TypeId    int
	AgentId   int
	ReqData   string
}

type GetMd5SignRQ struct {
	XMLName xml.Name `xml:"MD5"`
	Value   string   `xml:"String"`
	Key     string   `xml:"md5key"`
}

type GetMd5SignRS struct {
	XMLName xml.Name `xml:"MD5"`
	Sign    string   `xml:"md5value"`
}

type PolicyList struct {
	XMLName  xml.Name `xml:"PolicyList"`
	UserName string   `xml:"username,attr"`
	Policy   Policy   `xml:"Policy"`
}

type Policy struct {
	BusinessLogic   string `xml:"BusinessLogic,attr"`
	Insurance       string `xml:"Insurance"`
	MainGlausesCode string `xml:"MainGlausesCode"`
	HolderName      string `xml:"HolderName"`
	RecognizeeName  string `xml:"RecognizeeName"`
	PackQty         string `xml:"PackQty"`
	GoodsName       string `xml:"GoodsName"`
	GoodsTypeNo     string `xml:"GoodsTypeNo"`
	TransportType   string `xml:"TransportType"`
	Transport       string `xml:"Transport"`
	FromLoc         string `xml:"FromLoc"`
	ToLoc           string `xml:"ToLoc"`
	DepartureDate   string `xml:"DepartureDate"`
	EffDate         string `xml:"EffDate"`
	CurrencyID      string `xml:"CurrencyID"`
	InsuredAmount   string `xml:"InsuredAmount"`
	Ratio           string `xml:"Ratio"`
	EndCurrencyID   string `xml:"EndCurrencyID"`
	MD5Key          string `xml:"MD5Key"`
}

type MailBodyWrap struct {
	WaybillId int
	Amount    float32
	Insurance data.InsuranceDto
}

const (
	Header = `<?xml version="1.0" encoding="GBK"?>`
)

var env string
var userName = "DZGJ254"
var md5Key = "123456"
var getMd5SignUrl = "http://202.108.173.172:8201/ecargo/xmlDeal!md5InterfaceAction.action"
var insureUrl = "http://202.108.173.172:8201/ecargo/xmlDeal!xmlDealAction.action"
var mailNotifyUrl = "http://api.sendcloud.net/apiv2/mail/send"

var mailTo = "Chinalife_JJ@163.com"

//var mailTo = "gost102@sina.com"
var mailChn = make(chan MailBodyWrap)

func InitInsurance(runmode string) {
	env = runmode
	go func() {
		for {
			doSendMail()
		}
	}()
}

func PreInsure(records []InsuranceRecord) (err error) {
	repo := &data.InsuranceRepo{}
	if err = repo.BeginTx(); err == nil {
		defer func() {
			if err != nil {
				util.GetLogger().Error("[model-Insure] - error%s", err.Error())
			}
			repo.EndTx(err == nil)
		}()
		for _, v := range records {
			if repo.NewInsurance(data.InsuranceDto{
				MemberId:  v.MemberId,
				WaybillId: v.WaybillId,
				Amount:    v.Amount,
				TypeId:    v.TypeId,
				AgentId:   v.AgentId,
				State:     0,
				ReqData:   v.ReqData,
				ResData:   "",
			}); err != nil {
				break
			}
		}
	}
	return
}

func PostInsure(waybillId int) {
	var err error
	var list []data.InsuranceDto
	var repo data.InsuranceRepo
	if list, err = repo.GetNotCompleteInsurance(waybillId); err == nil {
		for _, val := range list {
			if val.TypeId == 0 { //费率
				sendMail(waybillId, val.Amount, val)
			}
			val.State = 1
			if err = repo.UpdateInsuranceCallback(val); err != nil {
				util.GetLogger().Error("[insurance-PostInsure - error:%s]", err.Error())
			}
		}
	} else {
		util.GetLogger().Error("[insurance-PostInsure - error:%s]", err.Error())
	}
}

func CancelInsuranceIfAny(waybillId int) error {
	var repo data.InsuranceRepo
	err := repo.Cancel(waybillId)
	return err
}

func InsureSample() (err error) {
	if utf8, err := xml.Marshal(&GetMd5SignRQ{Value: "AddFreightPolicyWebYDG0016301002016-11-21:172016-11-21:17100000.3", Key: md5Key}); err == nil {
		if gbk, err := utf8ToGbk(utf8); err == nil {
			if sign, err := doGetMd5Sign(append([]byte(Header), gbk...)); err == nil {
				if utf8, err := xml.Marshal(&PolicyList{
					UserName: userName,
					Policy: Policy{
						BusinessLogic:   "AddFreightPolicyWeb",
						Insurance:       "国内货物运输保险",
						MainGlausesCode: "YDG001",
						HolderName:      "张三",
						RecognizeeName:  "李四",
						PackQty:         "普通包装",
						GoodsName:       "打印机",
						GoodsTypeNo:     "630700",
						TransportType:   "公路",
						Transport:       "集卡",
						FromLoc:         "上海",
						ToLoc:           "北京",
						DepartureDate:   "2016-11-21:17",
						EffDate:         "2016-11-21:17",
						CurrencyID:      "CNY",
						InsuredAmount:   "10000",
						Ratio:           "0.3",
						EndCurrencyID:   "CNY",
						MD5Key:          sign,
					},
				}); err == nil {
					if gbk, err := utf8ToGbk(utf8); err == nil {
						if err = doInsure(gbk); err != nil {
							fmt.Println(err.Error())
						}
					}
				}
			} else {
				fmt.Println(err.Error())
			}
		} else {
			fmt.Println(err.Error())
		}

		return nil
	}

	return
}

func doGetMd5Sign(data []byte) (sign string, err error) {
	var body []byte
	resp, err := http.Post(getMd5SignUrl, "application/xml;charset=gbk", bytes.NewBuffer(data))
	if resp != nil {
		defer resp.Body.Close()
	}
	if err == nil {
		if body, err = ioutil.ReadAll(resp.Body); err == nil {
			rs := &GetMd5SignRS{}
			if err = unmarshalGbk(body, rs); err == nil {
				sign = rs.Sign
			}
		}
	}
	return
}

func doInsure(data []byte) (err error) {
	var body []byte
	fmt.Println(string(data))
	resp, err := http.Post(insureUrl, "application/xml;charset=gbk", bytes.NewBuffer(data))
	if resp != nil {
		defer resp.Body.Close()
	}
	if err == nil {
		if body, err = ioutil.ReadAll(resp.Body); err == nil {
			fmt.Println(string(body))
		}
	}
	return
}

func utf8ToGbk(utf8 []byte) ([]byte, error) {
	if gbk, err := ioutil.ReadAll(transform.NewReader(bytes.NewReader(utf8), simplifiedchinese.GBK.NewDecoder())); err == nil {
		return gbk, nil
	} else {
		return nil, err
	}
}

func unmarshalGbk(x []byte, val interface{}) error {
	decoder := xml.NewDecoder(bytes.NewReader(x))
	decoder.CharsetReader = func(s string, r io.Reader) (io.Reader, error) {
		return charset.NewReader(r, s)
	}
	return decoder.Decode(val)
}

func sendMail(waybillId int, amount float32, dto data.InsuranceDto) {
	if env == "prod" || env == "uat" {
		mailChn <- MailBodyWrap{WaybillId: waybillId, Amount: amount, Insurance: dto}
	}
}

func doSendMail() {

	mailBodyWrap := <-mailChn

	var err error
	var orderRepo data.OrderRepo
	var mbrRepo data.MemberRepo
	var insuranceRepo data.InsuranceRepo
	var waybillDto data.WaybillDetailDto
	var resp *http.Response
	var sendMailResBody []byte
	if waybillDto, err = orderRepo.GetWaybillDetail(mailBodyWrap.WaybillId); err == nil {
		var l Logistics
		var g General
		var mbrDto data.MemberDto
		var idcard string
		var orderNo ID
		vehicleNo := waybillDto.VehicleNo
		startArea := fmt.Sprintf("%s%s", l.GetAreaFullName(waybillDto.StartArea), waybillDto.StartAddr)
		endArea := fmt.Sprintf("%s%s", l.GetAreaFullName(waybillDto.EndArea), waybillDto.EndAddr)
		vehicle := g.GetDict("110")[strconv.Itoa(waybillDto.VehicleType)]
		cargoOwnerPhone := waybillDto.CargoOwnerPhone
		if mbrDto, err = mbrRepo.GetMemberInfo(waybillDto.CarrierOwnerId); err == nil {
			idcard = mbrDto.IDCardNo
		}
		departureDate, err := insuranceRepo.GetContractTime(mailBodyWrap.WaybillId)
		orderNo.Encode(ID_Shard, ID_Ver, ID_Waybill_Category, int64(mailBodyWrap.WaybillId))
		cargoName := waybillDto.CargoName
		cargoCount := strconv.Itoa(waybillDto.CargoCount)
		cargoWeight := fmt.Sprintf("%.2f", waybillDto.CargoWeight)

		mail_tpl := url.Values{
			"apiUser":  {"quickly_test_nCE0yO"},
			"apiKey":   {"o988cyHfvpBbyEyT"},
			"from":     {"auto@quickly56.com"},
			"to":       {mailTo},
			"subject":  {"快来运投保单"},
			"html":     {template.GetInsuranceMailNotifyContent(vehicleNo, startArea, endArea, vehicle, fmt.Sprintf("%s %s", mbrDto.Name, idcard), cargoOwnerPhone, departureDate, string(orderNo), cargoName, cargoCount, cargoWeight, fmt.Sprintf("%g", mailBodyWrap.Amount), time.Now().Format("2006-01-02"))},
			"fromName": {"快来运"},
		}
		mailBodyWrap.Insurance.ReqData = fmt.Sprintf("%v", mail_tpl)
		resp, err = http.PostForm(mailNotifyUrl, mail_tpl)
		if resp.Body != nil {
			defer resp.Body.Close()
		}
		if err == nil {
			if sendMailResBody, err = ioutil.ReadAll(resp.Body); err == nil {
				mailBodyWrap.Insurance.ResData = string(sendMailResBody)
				//fmt.Println(string(sendMailResBody))
			}
		}
	}

	if err == nil {
		mailBodyWrap.Insurance.State = 1
	} else {
		util.GetLogger().Error("[insurance-sendmail - error:%s]", err.Error())
	}
	if err = insuranceRepo.UpdateInsuranceCallback(mailBodyWrap.Insurance); err != nil {
		util.GetLogger().Error("[insurance-sendmail - error:%s]", err.Error())
	}

}
